package demo8


// 适配器模式用于转换一种接口适配另一种接口。
// 实际使用中Adaptee一般为接口，并且使用工厂函数生成实例。
// 在Adapter中匿名组合Adaptee接口，所以Adapter类也拥有SpecificRequest实例方法，又因为Go语言中非入侵式接口特征，其实Adapter也适配Adaptee接口。

// adapter  Target  Adaptee  adapteeImpl  adapter
import "fmt"
// --------------------------------场景1-----------------------------------
// 官方的案例，适配器就是解决原有的功能满足不了现在需求的时候，用在的场景就是，持久化的时候，与DB进行交互的事件，
// 使用适配器的好处，就是可以根据不同的需求定制不同的适配器

// 目标适配器，要匹配的目标
type Target interface{
	Request() string
}

// 原适配器，已经无法满足当前条件
type Adaptee interface{
	SpecificRequest() string
}

type adapteeImpl struct{}

func NewAdapteeImpl() Adaptee{
	return &adapteeImpl{}
} 

func (*adapteeImpl)SpecificRequest() string{
	return "adapteeImpl  原适配器...."
}

type adapter struct{
	adaptee Adaptee
}

func NewAdaptee(adaptee Adaptee) Target{
	return &adapter{
		adaptee:adaptee,
	}
}

func (a *adapter)Request() string{
	fmt.Println("目标适配器........")
	// 可以在原适配器的基础上增加新功能或者修改新功能
	// do-something
	return a.adaptee.SpecificRequest()
	// do-something
}

// --------------------------------场景2-----------------------------------
// 需求：现在有一个插排，需要电压是220V 但是这个插头不满足就无法充电，现在插头最高电压要求是110V
// 分析: 需要将110V的插头 适配成220V然后才能使用，110v的已经无法满足需求了
// 领域分析： 源sourceplug  目标targetplug  | 功能实现都一样 charge  baseChare

// 源接口
type SourcePlug interface{
	BaseChare()
}

func NewSouceAdaptee() SourcePlug{
	return &sourceAdaptee{}
}

type sourceAdaptee struct{} 
func (*sourceAdaptee)BaseChare(){
	fmt.Println("-------- 110V -------")
}
// 目标，结果

type TargetPlug interface{
	Charge()
}

func NewTargetAdaptee(source SourcePlug) TargetPlug{
	return &targetAdaptee{
		source:source,
	}
}
type targetAdaptee struct{
	source SourcePlug
}
func (t *targetAdaptee)Charge(){
	fmt.Println("--------220v---------")
	fmt.Println("保留之前的功能如下：")
	t.source.BaseChare()
}

// --------------------------------场景3-----------------------------------
// 需求：需要保存数据到DB中 ： 将订单数据持久化到DB
// 分析：由于不敢保证以后订单存储是否会做调整或者修改持久化中间的过滤逻辑，此时这里使用到适配器来完成
// 至于这里为什么不用装饰器，和模板方法，因为这里是两个不同的实例之间的链接问题，
// 简单的说从服务到DB 两个不同的对象中间的接口使用适配器，装饰器还是本身上的使用，还是同一个方法，而模板方法呢则是相同的实例内部
// 为了实现和拓展新的迭代方法
// DDD设计: SourceOrder Save() 接口   TargetOrder Storage()

type SourceDataAdapter interface{
	// 最原始的适配器
	Storage() // 储存数据到DB
}

func NewSouceDataAdaptee() SourceDataAdapter{
	return &SourceDataAdaptee{}
}

// 最原始的适配器
type SourceDataAdaptee struct{}
func (*SourceDataAdaptee)Storage(){
	fmt.Println("存储数据到DB...........")
}

// 可拓展的适配器 ，可以根据不同的场景定制不同的适配器来满足当下需求
type TargetDataAdapter interface{
	Save()
}

func NewTargetDataAdaptee(sourceData SourceDataAdapter) TargetDataAdapter{
	return &TargetDataAdaptee{
		sourceData:sourceData,
	}
}
// 派生的目标适配器 该适配器急需要实现之前的功能，而且还要增加新的功能，
// 那么问题来了，如果修改功能的话怎么办呢，这里需要使用上面说的模板方法来实现
type TargetDataAdaptee struct{
	sourceData SourceDataAdapter
}
func (t *TargetDataAdaptee) Save(){
	fmt.Println("数据过滤..........")
	t.sourceData.Storage()
}

// --------------------------------场景4-----------------------------------

// 适配器模式，使用的场景，在demo中已经提及到了包括和某些设计模式的场景区分
// 该设计模式，主要是运用了目标适配器嵌套 源适配器的接口来实现的，通过目标适配器的实例来调用源适配器的方法来实现
// 同时在目标适配器增加新的功能，关于其他不同的适配器，可以在源适配器的基础之上进行拓展更多满足需求的功能
